
#include "etl_variant.h"

#include <string.h>
#include <stdlib.h>

using namespace etl;

etl_variant::etl_variant() :
  type( EMPTY ),
  numerics(),
  bytes( NULL ),
  bytesSize( 0 ),
  text()
{
  memset( &numerics, 0, sizeof( union etl_numeric_box ) );
}

etl_variant::etl_variant( const etl_variant& obj ) :
  type( EMPTY ),
  numerics(),
  bytes( NULL ),
  bytesSize( 0 ),
  text()
{
  memset( &numerics, 0, sizeof( union etl_numeric_box ) );
  copy( obj );
}

etl_variant::~etl_variant()
{
  if( bytes )
    free( bytes );
}

etl_variant& etl_variant::operator = ( const etl_variant& obj )
{
  return copy( obj );
}

etl_variant::etl_variant_type etl_variant::get_type()
{
  return type;
}

int etl_variant::set_signed_integer( long val )
{
  clear();
  type = SIGNED_INTEGER;
  numerics.s32 = val;
  return 0;
}

int etl_variant::set_unsigned_integer( unsigned long val )
{
  clear();
  type = UNSIGNED_INTEGER;
  numerics.u32 = val;
  return 0;
}

int etl_variant::set_floating_point( double val )
{
  clear();
  type = FLOATING_POINT;
  numerics.d64 = val;
  return 0;
}

int etl_variant::set_bytes( const unsigned char* data, unsigned long size )
{
  clear();

  bytes = (unsigned char*)malloc( size );

  if( bytes )
    {
      type = BYTES;
      memcpy( bytes, data, size );
      bytesSize = size;
      return 0;
    }

  return -1;
}

int etl_variant::set_string( etl_string val )
{
  clear();
  type = TEXT;
  text = val;
  return 0;
}

int etl_variant::get_signed_integer( long& val )
{
  if( type == SIGNED_INTEGER )
    {
      val = numerics.s32;
      return 0;
    }
  return -1;
}

int etl_variant::get_unsigned_integer( unsigned long& val )
{
  if( type == UNSIGNED_INTEGER )
    {
      val = numerics.u32;
      return 0;
    }
  return -1;
}

int etl_variant::get_floating_point( double& val )
{
  if( type == FLOATING_POINT )
    {
      val = numerics.d64;
      return 0;
    }
  return -1;
}

int etl_variant::get_bytes( unsigned char** data, unsigned long& size )
{
  if( type == BYTES )
    {
      *data = bytes;
      size = bytesSize;
      return 0;
    }
  return -1;
}

int etl_variant::get_string( etl_string& val )
{
  if( type == TEXT )
    {
      val = text;
      return 0;
    }
  return -1;
}

int etl_variant::clear()
{
  type = EMPTY;
  memset( &numerics, 0, sizeof( union etl_numeric_box ) );
  if( bytes )
    free( bytes );
  bytes = NULL;
  bytesSize = 0;
  text = "";
  return 0;
}

etl_variant& etl_variant::copy( const etl_variant& obj )
{
  clear();

  type = obj.type;

  memcpy( &numerics, &obj.numerics, sizeof( union etl_numeric_box ) );
  
  if( obj.bytes )
    {
      bytes = (unsigned char*)malloc( obj.bytesSize );

      if( bytes )
        {
          bytesSize = obj.bytesSize;
          memcpy( bytes, obj.bytes, bytesSize );
        }
    }

  text = obj.text;

  return *this;
}
